<template>
  <div>
    <canvas
      id="fireworks-1"
      class="fixed top-0 left-0 -z-999 pointer-events-none"
    ></canvas>
    <canvas
      id="fireworks-2"
      class="fixed top-0 left-0 -z-999 pointer-events-none"
    ></canvas>
    <modal msg="🥰🥰💖💖亲爱的 me，七夕节快乐哟！😍😍爱爱爱爱爱爱爱爱你，永远爱你！！！💖💖🥰🥰"></modal>
  </div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted } from "vue";
import modal from './myModal.vue'



const rockets = [] as any[];
const shards = [] as any[];
const targets = [] as any[];
const fidelity = 3;
let counter = 0;

let c2: HTMLCanvasElement;
let c3: HTMLCanvasElement;

let ctx2: CanvasRenderingContext2D;
let ctx3: CanvasRenderingContext2D;

// 动画循环
// 组件卸载时记得停止计时器，否则造成内存泄漏，loop 还会继续循环执行
let loop = () => {
  // background-image: linear-gradient(to top, #30cfd0 0%, #330867 100%);

  // ctx2.fillStyle = "rgba(138,43,226, .1)";
  // ctx2.fillRect(0, 0, c2.width, c2.height);
  const gradient = ctx2.createLinearGradient(0, 0, 0, c2.height);
  gradient.addColorStop(0, "rgba(0, 0, 0, .1)");
  gradient.addColorStop(0.7, "rgba(37, 35, 36, .1)");
  gradient.addColorStop(1, "rgba(59, 59, 59, .1)");
  ctx2.fillStyle = gradient;
  ctx2.fillRect(0, 0, c2.width, c2.height);
  // 不需要清空，否则烟花没有拖尾效果
  // ctx2.clearRect(0, 0, c2.width, c2.height);
  counter += 1;

  if (counter % 15 === 0) {
    rockets.push(new Rocket());
  }
  rockets.forEach((r, i) => {
    r.draw();
    r.update();
    if (r.ySpeed > 0) {
      r.explode();
      rockets.splice(i, 1);
    }
  });

  shards.forEach((s, i) => {
    s.draw();
    s.update();

    if (s.timer >= s.ttl || s.lightness >= 99) {
      ctx3.fillRect(s.target.x, s.target.y, fidelity + 1, fidelity + 1);
      shards.splice(i, 1);
    }
  });

  requestAnimationFrame(loop);
};
// 烟花火箭
class Rocket {
  x: number;
  y: number;
  angle: number;
  blastSpeed: number;
  shardCount: number;
  xSpeed: number;
  ySpeed: number;
  hue: number;
  trail: never[];
  constructor() {
    const quarterW = c2.width / 4;
    this.x = quarterW + Math.random() * (c2.width - quarterW);
    this.y = c2.height - 15;
    this.angle = (Math.random() * Math.PI) / 4 - Math.PI / 6;
    this.blastSpeed = 6 + Math.random() * 7;
    this.shardCount = 15 + Math.floor(Math.random() * 15);
    this.xSpeed = Math.sin(this.angle) * this.blastSpeed;
    this.ySpeed = -Math.cos(this.angle) * this.blastSpeed;
    this.hue = Math.floor(Math.random() * 360);
    this.trail = [];
  }
  draw() {
    ctx2.save();
    ctx2.translate(this.x, this.y);
    ctx2.rotate(Math.atan2(this.ySpeed, this.xSpeed) + Math.PI / 2);
    ctx2.fillStyle = `hsl(${this.hue}, 100%, 50%)`;
    ctx2.fillRect(0, 0, 5, 15);
    ctx2.restore();
  }
  update() {
    this.x = this.x + this.xSpeed;
    this.y = this.y + this.ySpeed;
    this.ySpeed += 0.1;
  }

  explode() {
    for (let i = 0; i < 70; i++) {
      shards.push(new Shard(this.x, this.y, this.hue));
    }
  }
}
// 辅助功能
const lerp = (a, b, t) => (Math.abs(b - a) > 0.1 ? a + t * (b - a) : b);
// 烟花碎片
class Shard {
  x: any;
  y: any;
  hue: any;
  lightness: number;
  size: number;
  xSpeed: number;
  ySpeed: number;
  target: any;
  ttl: number;
  timer: number;
  constructor(x, y, hue) {
    this.x = x;
    this.y = y;
    this.hue = hue;
    this.lightness = 50;
    this.size = 10 + Math.random() * 10;
    const angle = Math.random() * 2 * Math.PI;
    const blastSpeed = 1 + Math.random() * 6;
    this.xSpeed = Math.cos(angle) * blastSpeed;
    this.ySpeed = Math.sin(angle) * blastSpeed;
    this.target = getTarget();
    this.ttl = 100;
    this.timer = 0;
  }
  draw() {
    ctx2.fillStyle = `hsl(${this.hue}, 100%, ${this.lightness}%)`;
    ctx2.beginPath();
    ctx2.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
    ctx2.closePath();
    ctx2.fill();
  }
  update() {
    if (this.target) {
      const dx = this.target.x - this.x;
      const dy = this.target.y - this.y;
      const dist = Math.sqrt(dx * dx + dy * dy);
      const a = Math.atan2(dy, dx);
      const tx = Math.cos(a) * 5;
      const ty = Math.sin(a) * 5;
      this.size = lerp(this.size, 1.5, 0.05);

      if (dist < 5) {
        this.lightness = lerp(this.lightness, 100, 0.01);
        this.xSpeed = this.ySpeed = 0;
        this.x = lerp(this.x, this.target.x + fidelity / 2, 0.05);
        this.y = lerp(this.y, this.target.y + fidelity / 2, 0.05);
        this.timer += 1;
      } else if (dist < 10) {
        this.lightness = lerp(this.lightness, 100, 0.01);
        this.xSpeed = lerp(this.xSpeed, tx, 0.1);
        this.ySpeed = lerp(this.ySpeed, ty, 0.1);
        this.timer += 1;
      } else {
        this.xSpeed = lerp(this.xSpeed, tx, 0.02);
        this.ySpeed = lerp(this.ySpeed, ty, 0.02);
      }
    } else {
      this.ySpeed += 0.05;
      // this.xSpeed = lerp(this.xSpeed, 0, 0.1);
      this.size = lerp(this.size, 1, 0.05);

      if (this.y > c2.height) {
        shards.forEach((shard, idx) => {
          if (shard === this) {
            shards.splice(idx, 1);
          }
        });
      }
    }
    this.x = this.x + this.xSpeed;
    this.y = this.y + this.ySpeed;
  }
}
// 获取目标
function getTarget() {
  if (targets.length > 0) {
    const idx = Math.floor(Math.random() * targets.length);
    let { x, y } = targets[idx];
    targets.splice(idx, 1);

    x += c2.width / 2 - 100 / 2;
    y += c2.height / 2 - 100 / 2;

    return { x, y };
  }
}
// 绘制canvas
onMounted(() => {
  c2 = document.getElementById("fireworks-1") as HTMLCanvasElement;
  c3 = document.getElementById("fireworks-2") as HTMLCanvasElement;
  c2.width = c3.width = window.innerWidth;
  c2.height = c3.height = window.innerHeight;

  [ctx2, ctx3] = [c2, c3].map((c) => c.getContext("2d")!);

  ctx3.fillStyle = "#ffffff";
  ctx3.shadowColor = "#cccccc";
  ctx3.shadowBlur = 5;
  loop();
});
onUnmounted(() => {
  loop = () => {};
});
</script>
